<?php
/**
 * +----------------------------------------------------------------------
 * | 管理员列表模型
 * +----------------------------------------------------------------------
 *                      .::::.
 *                    .::::::::.            | AUTHOR: siyu
 *                    :::::::::::           | EMAIL: 407593529@qq.com
 *                 ..:::::::::::'           | DATETIME: 2020/03/08
 *             '::::::::::::'
 *                .::::::::::
 *           '::::::::::::::..
 *                ..::::::::::::.
 *              ``::::::::::::::::
 *               ::::``:::::::::'        .:::.
 *              ::::'   ':::::'       .::::::::.
 *            .::::'      ::::     .:::::::'::::.
 *           .:::'       :::::  .:::::::::' ':::::.
 *          .::'        :::::.:::::::::'      ':::::.
 *         .::'         ::::::::::::::'         ``::::.
 *     ...:::           ::::::::::::'              ``::.
 *   ```` ':.          ':::::::::'                  ::::..
 *                      '.:::::'                    ':'````..
 * +----------------------------------------------------------------------
 */

namespace app\common\model;

// 引入框架内置类
use think\facade\Db;
use think\facade\Event;
use think\facade\Request;
use think\facade\Session;

// 引入构建器
use app\common\facade\MakeBuilder;

class Admin extends Base
{
    // 定义时间戳字段名
    protected $createTime = 'create_time';
    protected $updateTime = 'update_time';

    // 获取列表
    public static function getList(array $where = [], int $pageSize = 0, array $order = ['sort', 'id' => 'desc'])
    {
        if ($pageSize) {
            $list = self::where($where)
                ->order($order)
                ->paginate([
                    'query'     => Request::get(),
                    'list_rows' => $pageSize,
                ]);
        } else {
            $list = self::where($where)
                ->order($order)
                ->select();
        }

        $auth = new \Auth();
        foreach ($list as $k => $v) {
            $title  = '';
            $groups = $auth->getGroups($v->id);
            foreach ($groups as $group) {
                $title .= $group['title'] . ',';
            }
            $title                  = rtrim($title, ',');
            $list[$k]['group_name'] = $title;
        }
        return MakeBuilder::changeTableData($list, 'Admin');
    }

    /**
     * 管理员登录校验
     * @return array|\think\response\Json
     * @throws \think\Exception
     */
    public static function checkLogin()
    {
        // 查找所有系统设置表数据
        $system = \app\common\model\System::find(1);
        // 定义登录限制配置
        $MAX_LOGIN_ATTEMPTS = intval(config('app.login_lock.max_attempts')); // 从配置中获取最大尝试次数
        $LOCK_TIME         = intval(config('app.login_lock.lock_time'));     // 从配置中获取锁定时间（分钟）

        $username  = Request::param("username");
        $password  = Request::param("password");

        $open_code = $system['code'];
        if ($open_code) {
            $code = Request::param("vercode");
            if (!captcha_check($code)) {
                $data = ['error' => '1', 'msg' => '验证码错误'];
                return json($data);
            }
        }
        $result = self::where(['username' => $username])->find();
        // 检查账号是否存在
        if (empty($result)) {
            $data = ['error' => '1', 'msg' => '帐号或密码错误'];
            return json($data);
        }

        // 检查是否被锁定
        if ($result['login_attempts'] >= $MAX_LOGIN_ATTEMPTS) {
            $lockTime = $result['last_login_attempt'] + ($LOCK_TIME * 60);
            if (time() < $lockTime) {
                $remainingTime = ceil(($lockTime - time()) / 60);
                return json([
                    'error' => '1', 
                    'msg' => "账号已被锁定，请{$remainingTime}分钟后再试"
                ]);
            }
            // 锁定时间已过，重置登录尝试次数
            self::where('id', '=', $result['id'])->update([
                'login_attempts' => 0,
                'last_login_attempt' => null
            ]);
        }
        // 验证密码
        if (!password_verify($password, $result->password)) {
            // 更新登录失败次数和时间
            $attempts = $result['login_attempts'] + 1;
            self::where('id', '=', $result['id'])->update([
                'login_attempts' => $attempts,
                'last_login_attempt' => time()
            ]);
            
            $remainingAttempts = $MAX_LOGIN_ATTEMPTS - $attempts;
            $msg = $remainingAttempts > 0 ? 
                "帐号或密码错误，还剩{$remainingAttempts}次尝试机会" : 
                "登录失败次数过多，账号已被锁定{$LOCK_TIME}分钟";
                
            return json(['error' => '1', 'msg' => $msg]);
        }
       
        $check = Request::checkToken('__token__');
        if (false === $check) {
            $data = ['error' => '2', 'msg' => '验证有误'];
            return json($data);
        }
        if ($result['status'] == 1) {
            $uid = $result['id'];
            // 更新登录IP和登录时间
            self::where('id', '=', $result['id'])
                ->update([
                    'login_attempts' => 0,
                    'last_login_attempt' => null,
                    'login_time' => time(), 
                    'login_ip' => Request::ip()
                ]);

            // 查找规则
            $rules = Db::name('auth_group_access')
                ->alias('a')
                ->leftJoin('auth_group ag', 'a.group_id = ag.id')
                ->field('a.group_id,ag.rules,ag.title')
                ->where('uid', $uid)
                ->find();
            // 查询所有不验证的方法并放入规则中
            $authOpen  = AuthRule::where('auth_open', '=', '0')
                ->select();
            $authRole  = AuthRule::select();
            $authOpens = [];
            foreach ($authOpen as $k => $v) {
                $authOpens[] = $v['id'];
                // 查询所有下级权限
                $ids = getChildsRule($authRole, $v['id']);
                foreach ($ids as $kk => $vv) {
                    $authOpens[] = $vv['id'];
                }
            }

            $authOpensStr   = !empty($authOpens) ? implode(",", $authOpens) : '';
            $rules['rules'] = $rules['rules'] . $authOpensStr;

            // 重新查询要赋值的数据[原因是toArray必须保证find的数据不为空，为空就报错]
            $result = self::where(['username' => $username])->find();
            Session::set('admin', [
                'id'         => $result['id'],
                'username'   => $result['username'],
                'login_time' => date('Y-m-d H:i:s', $result['login_time']),
                'login_ip'   => $result['login_ip'],
                'nickname'   => $result['nickname'],
                'image'      => $result['image'],
            ]);
            Session::set('admin.group_id', $rules['group_id']);
            Session::set('admin.rules', explode(',', $rules['rules']));
            Session::set('admin.title', $rules['title']);

            // 触发登录成功事件
            Event::trigger('AdminLogin', $result);

            $data = ['error' => '0', 'href' => url('Index/index')->__toString(), 'msg' => '登录成功'];
            return json($data);
        } else {
            return json(['error' => 1, 'msg' => '用户已被禁用!']);
        }

    }

}